package com.yygo.webapp.controller.loanrequest;

import com.yygo.Constants;
import com.yygo.configentity.feedback.RoleFeedback;
import com.yygo.model.*;
import com.yygo.model.enums.FeedbackStatus;
import com.yygo.model.enums.FeedbackType;
import com.yygo.model.enums.Phase;
import com.yygo.model.vo.FeedbackVO;
import com.yygo.model.vo.LoanRequestVO;
import com.yygo.model.vo.TalkrecordVO;
import com.yygo.service.FeedbackManager;
import com.yygo.service.RoleActionsConfigurer;
import com.yygo.util.DateUtil;
import com.yygo.webapp.controller.SearchForm;
import com.yygo.webapp.helper.ExtendedPaginatedList;
import com.yygo.webapp.helper.PaginateListFactory;
import com.yygo.websocket.SystemWebSocketHandler;
import org.appfuse.service.GenericManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ExtendedModelMap;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.nio.file.AccessDeniedException;
import java.security.Principal;
import java.util.*;

@Controller
@RequestMapping("/loanRequests")
public class LoanRequestController extends BaseLoanRequestFormController {

    @Autowired
    private FeedbackManager feedbackManager;

    private GenericManager<TalkRecord, Long> talkRecordManager;
    @Autowired
    public void setTalkRecordManager(GenericManager talkRecordManager) {this.talkRecordManager = talkRecordManager;}

    private PaginateListFactory paginateListFactory;
    @Autowired
    public void setPaginateListFactory(PaginateListFactory paginateListFactory) {
        this.paginateListFactory = paginateListFactory;
    }

    @Autowired
    private RoleActionsConfigurer roleActionsConfigurer;

    @RequestMapping(method = RequestMethod.GET)
    @ModelAttribute
    public Model handleRequest(@RequestParam(required = false, value = "date") Date date, @RequestParam(required = false, value = "status", defaultValue = "all") String status,
                               @RequestParam(required = false, value = "number") String number, @RequestParam(required = false, value = "name") String name,
                               HttpServletRequest request, Principal principal)
    throws Exception {
        ExtendedPaginatedList paginatedList = paginateListFactory
                .getPaginatedListFromRequest(request);

        Model model = new ExtendedModelMap();

        if (date == null) {
            date = DateUtil.getDateBefore(10);
        }
        User loginUser = userManager.getUserByUsername(principal.getName());
        List<LoanRequest> list = loanRequestManager.searchLoanRequests(loginUser, status, date, number, name, paginatedList);
        setGrabs(list, loginUser);
        model.addAttribute("loanRequestList", paginatedList);

        model.addAttribute("loginUser", loginUser);
        model.addAttribute("roleActionsConfigurer", roleActionsConfigurer);

        return model;
    }

    private void setGrabs(List<LoanRequest> list, User loginUser) {
        for (LoanRequest loanRequest : list) {
            for (Role role : loginUser.getRoles()) {
                if (roleActionsConfigurer.isGrab(role.getName(), loanRequest.getPhase().toString())) {
                    loanRequest.setCanGrab(true);
                    continue;
                }
            }
        }
    }

    @ModelAttribute
    public SearchForm onForm(@RequestParam(required = false, value = "date") Date date, @RequestParam(required = false, value = "status", defaultValue = "all") String status,
                             @RequestParam(required = false, value = "number") String number, @RequestParam(required = false, value = "name") String name) {
        SearchForm form = new SearchForm();
        form.setStatus(status);
        if (date == null) {
            date = DateUtil.getDateBefore(10);
        }
        form.setDate(date);
        form.setNumber(number);
        form.setName(name);
        return form;
    }

    @RequestMapping(value = "/transferOperator", method = RequestMethod.GET)
    public String transferOperator(@RequestParam(required = true, value = "reqId") Long reqId, @RequestParam(required = true, value = "auditor") String auditor, HttpServletRequest request, Principal principal) {
        LoanRequest loanRequest = loanRequestManager.loadWholeLoanRequest(reqId);
        User auditUser = userManager.getUserByUsername(auditor);
        transferAuditUser(loanRequest, auditUser, request.getLocale(), principal);
        return "redirect:/loanRequests";
    }

    public void transferAuditUser(LoanRequest loanRequest, User user, Locale locale, Principal principal) {
        User loginUser = userManager.getUserByUsername(principal.getName());
        loanRequest.setAuditUser(user);
        // add activity
        String activity = getText("loanRequest.activity.transferOperator", user.getUsername(), locale);
        Activity activityObj = new Activity(principal.getName(), activity);
        activityObj.setRole(loginUser.getRoleList().get(0).getValue());
        activityObj.setLoanRequest(loanRequest);
        loanRequest.getActivities().add(activityObj);
        loanRequestManager.saveLoanRequest(loanRequest);
    }

    @RequestMapping(value = "/activities", method = RequestMethod.GET)
    @ResponseBody
    public List<Activity> getActivities(@RequestParam(required = true, value = "reqId") Long reqId) {
        LoanRequest loanRequest = loanRequestManager.loadWholeLoanRequest(reqId);
        List<Activity> list = loanRequest.getActivities();
        for (Activity activity: list) {
            activity.setLoanRequest(null);
        }
        Collections.sort(list, new Comparator<Activity>() {
            @Override
            public int compare(Activity o1, Activity o2) {
                return o1.getTime().before(o2.getTime())? 1 : -1;
            }
        });
        return list;
    }

    @RequestMapping(value = "/feedbacks", method = RequestMethod.GET)
    @ResponseBody
    public List<Feedback> getFeedback(@RequestParam(required = true, value = "reqId") Long reqId, HttpServletRequest request ) {
        LoanRequest loanRequest = loanRequestManager.loadWholeLoanRequest(reqId);
        List<Feedback> list = loanRequest.getFeedbackList();
        for (Feedback feedback: list) {
            feedback.setLoanRequest(null);
            feedback.setReadableStatus(getText("REQUEST_STATUS_".concat(feedback.getReqStatus().toString()),request.getLocale()));
        }
        Collections.sort(list, new Comparator<Feedback>() {
            @Override
            public int compare(Feedback o1, Feedback o2) {
                return o1.getTime().before(o2.getTime())? 1 : -1;
            }
        });
        return list;
    }
  @RequestMapping(value = "/feedback/read", method = RequestMethod.GET)
  @ResponseBody
  public void setFeedbackRead(@RequestParam(required = true, value = "reqId") Long reqId,@RequestParam(required = false, value = "feedBackId") Long feedBackId, HttpServletRequest request ) {
    LoanRequest loanRequest = loanRequestManager.loadWholeLoanRequest(reqId);
    List<Feedback> list = loanRequest.getFeedbackList();
    for (Feedback feedback: list) {
      if(feedback.getId()==feedBackId){
        feedback.setFeedbackStatus(FeedbackStatus.End);
      }
    }
    loanRequestManager.saveLoanRequest(loanRequest);
  }

    @RequestMapping(value = "/feedbacks", method = RequestMethod.POST)
    @ResponseBody
    public FeedbackVO addFeedback(@RequestParam(required = true, value = "reqId") Long reqId, @RequestParam(required = true, value = "content") String content, @RequestParam(required = true, value = "type") String type,
                            @RequestParam(required = true, value = "require_back") Boolean require_back,@RequestParam(required = false, value = "feedBackId") Long feedBackId, HttpServletRequest request,  Principal principal) throws AccessDeniedException, IllegalAccessException {
        LoanRequest loanRequest = loanRequestManager.loadWholeLoanRequest(reqId);
        User loginUser = userManager.getUserByUsername(principal.getName());
        SystemWebSocketHandler systemWebSocketHandler = new SystemWebSocketHandler();

      if(feedBackId!=null){
        for( Feedback feedback: loanRequest.getFeedbackList()){
          if(feedback.getId()==feedBackId){
            feedback.setFeedbackStatus(FeedbackStatus.Returned);
            feedback.setContent(content);

            log.debug("Sending message via web socket...");
            systemWebSocketHandler.sendMessageToUser(feedback.getFeedbackRequester().getUsername(), loanRequest.getId().toString());

          }
        }
        loanRequestManager.saveLoanRequest(loanRequest);
        return  new FeedbackVO();
      }
        Feedback feedback = new Feedback();
        feedback.setContent(content);
        feedback.setReqStatus(loanRequest.getStatus());
        feedback.setTime(new Date());
        feedback.setLoanRequest(loanRequest);
        feedback.setRequireBack(require_back);
        feedback.setFeedbackRequester(loginUser);

        FeedbackStatus feedbackStatus = FeedbackStatus.Requested;
        feedback.setFeedbackStatus(feedbackStatus);
        // add activity
        String activity = getText("loanRequest.activity.addFeedback",  new String[]{loginUser.getUsername(), content}, request.getLocale());
        Activity activityObj = new Activity(principal.getName(), activity);
        activityObj.setRole(loginUser.getRoleList().get(0).getValue());
        activityObj.setLoanRequest(loanRequest);
        loanRequest.getActivities().add(activityObj);
        // add feedback type parameter
        FeedbackType feedbackType = FeedbackType.valueOf(type);
        feedback.setFeedbackType(feedbackType);

        // determine feedback target
        User feedbackTarget = null;
        boolean isDealer = false;
        if (request.isUserInRole(Constants.DEALER_USER_ROLE)) {
            isDealer = true;
        }
        /*boolean isDealer = false;
        if (request.isUserInRole(Constants.DEALER_USER_ROLE)) {
            isDealer = true;
        }
        boolean isBooking = false;
        if (request.isUserInRole(Constants.Booking_ROLE)) {
            isBooking = true;
        }
        boolean isSCA = false;
        if (request.isUserInRole(Constants.SCA_ROLE)) {
            isSCA = true;
        }

        if (loanRequest.getPhase().equals(Phase.ca_audit) || loanRequest.getPhase().equals(Phase.sca_audit) || loanRequest.getPhase().equals(Phase.booking_audit)) { // during request audit
            if (isDealer) {
                feedback.setFeedbackTarget(loanRequest.getAuditUser());
            } else {
                feedback.setFeedbackTarget(loanRequest.getDealerUser());
            }
        } else if (loanRequest.getPhase().equals(Phase.qualification_audit)) { // during qualification audit
            if (isSCA) {
                feedback.setFeedbackTarget(loanRequest.getAuditUser());
            } else {
                feedback.setFeedbackTarget(getHistoryUser(loanRequest, Constants.SCA_ROLE));
            }
        } else if (loanRequest.getPhase().equals(Phase.bank_loan_audit) || loanRequest.getPhase().equals(Phase.insurance_loan_audit)) { // during loan audit
            if (isBooking) {
                feedback.setFeedbackTarget(loanRequest.getAuditUser());
            } else {
                feedback.setFeedbackTarget(getHistoryUser(loanRequest, Constants.Booking_ROLE));
            }
        }*/

        RoleFeedback roleFeedback = getRoleFeedback(loanRequest, loginUser);
        if(feedback.getFeedbackType().equals(FeedbackType.FileRecAndSend) && isDealer){
            feedback.setFeedbackTarget(getHistoryUser(loanRequest, Constants.Material_Receive_ROLE));
        }else if (roleFeedback != null) {
            feedback.setFeedbackTarget(getHistoryUser(loanRequest, roleFeedback.getToRole()));
            //feedback.setRequireBack(roleFeedback.isRequireRespond());
        }

        loanRequest.getFeedbackList().add(feedback);
        loanRequestManager.saveLoanRequest(loanRequest);

        log.debug("entering 'addFeedback' method...");
        //feedbackManager.save(feedback);
        log.debug("Sending message via web socket...");
        systemWebSocketHandler.sendMessageToUser(feedback.getFeedbackTarget().getUsername(), loanRequest.getId().toString());

        String reqStatus = getText("REQUEST_STATUS_".concat(loanRequest.getStatus().toString()), request.getLocale());
        //String feedbackStatusStr = getText("FEEDBACK_STATUS_".concat(feedbackStatus.toString()), request.getLocale());
        FeedbackVO feedbackVO = new FeedbackVO(feedback);
        feedbackVO.setReqStatus(reqStatus);
        feedbackVO.setFeedbackType(getText("FEEDBACK_TYPE_".concat(feedbackType.toString()), request.getLocale()));

        return feedbackVO;
    }

    @RequestMapping(value = "/talkrecords", method = RequestMethod.GET)
    @ResponseBody
    public List<TalkRecord> getTalkRecords(@RequestParam(required = true, value = "reqId") Long reqId, HttpServletRequest request ) {
        LoanRequest loanRequest = loanRequestManager.loadWholeLoanRequest(reqId);
        List<TalkRecord> list = loanRequest.getTalkRecordList();
        for (TalkRecord talkRecord: list) {
            talkRecord.setLoanRequest(null);
        }
        Collections.sort(list, new Comparator<TalkRecord>() {
            @Override
            public int compare(TalkRecord o1, TalkRecord o2) {
                return o1.getTime().before(o2.getTime())? 1 : -1;
            }
        });
        return list;
    }

    @RequestMapping(value = "/talkrecords", method = RequestMethod.POST)
    @ResponseBody
    public TalkrecordVO addTalkRecord(@RequestParam(required = true, value = "reqId") Long reqId, @RequestParam(required = true, value = "content") String content,
                              @RequestParam(required = true, value = "number") String number,HttpServletRequest request,  Principal principal) throws AccessDeniedException {
        LoanRequest loanRequest = loanRequestManager.get(reqId);
        User loginUser = userManager.getUserByUsername(principal.getName());
        TalkRecord talkRecord = new TalkRecord();
        talkRecord.setOperator(loginUser.getUsername());
        talkRecord.setTime(new Date());
        talkRecord.setContent(content);
        talkRecord.setNumber(number);
        talkRecord.setLoanRequest(loanRequest);

        talkRecordManager.save(talkRecord);

        TalkrecordVO talkrecordVO = new TalkrecordVO(talkRecord.getOperator());
        return talkrecordVO;
    }

    @RequestMapping(value = "/getLoanRequest", method = RequestMethod.GET)
    @ResponseBody
    public LoanRequestVO getLoanRequest(@RequestParam(required = true, value = "reqId") Long reqId,HttpServletRequest request) {
        LoanRequest loanRequest = loanRequestManager.get(reqId);
        LoanRequestVO vo = new LoanRequestVO();
        vo.setId(loanRequest.getId());
        //vo.setFeedbackType(getText("FEEDBACK_STATUS_".concat(loanRequest.getFeedbackType().toString()), request.getLocale()));
        vo.setNumber(loanRequest.getNumber());
        vo.setAuditComment(loanRequest.getAuditComment());
        vo.setDealerComment(loanRequest.getDealerComment());
        vo.setAuditUser(loanRequest.getAuditUser().getUsername());
        vo.setStatus(getText("REQUEST_STATUS_".concat(loanRequest.getStatus().toString()), request.getLocale()));
        return vo;
    }


    @RequestMapping(value = "/getTransferUsers", method = RequestMethod.GET)
    @ResponseBody
    public List<LabelValue> getTransferUsers(@RequestParam(required = true, value = "reqId") Long reqId) {
        LoanRequest loanRequest = loanRequestManager.get(reqId);
        List<User> users = new ArrayList<>();
        if (loanRequest.getPhase().equals(Phase.bank_credit_audit) ||
                loanRequest.getPhase().equals(Phase.bank_loan_audit)){
            Bank bank = loanRequest.getAuditUser().getBank();
            users = userManager.getUsersByBankAndRole(loanRequest.getAuditUser().getRoleList().get(0).getValue(), bank);
        }
        else {
            users = userManager.getUsersByRole(loanRequest.getAuditUser().getRoleList().get(0).getValue());
        }
        List<LabelValue> list = new ArrayList<>();
        for (User user: users) {
            list.add(new LabelValue(user.getUsername(), user.getUsername()));
        }
        return list;
    }

    @ModelAttribute("availableDealerRequestStatus")
    protected List<LabelValue> loadAvailableDealerStatus() {
        return getList(Constants.AVAILABLE_DEALER_REQUEST_STATUS, "REQUEST_STATUS");
    }

    @ModelAttribute("availableLoanRequestStatus")
    protected List<LabelValue> loadAvailableLoanStatus() {
        return getList(Constants.AVAILABLE_LOAN_REQUEST_STATUS, "REQUEST_STATUS");
    }
}
